/*
 * Initializer.java
 *
 * Copyright 2007, 2008 Tiberiumlabs
 *
 * This file is part of Tiberiumlabs Lailaps.
 *
 * Tiberiumlabs Lailaps is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Tiberiumlabs Lailaps is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.tiberiumlabs.lailaps;

import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Locale;
import javax.swing.JFrame;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
import org.apache.commons.logging.LogFactory;
import org.tiberiumlabs.lailaps.gui.EditDownloadDialog;
import org.tiberiumlabs.lailaps.gui.GUIBuilder;
import org.tiberiumlabs.lailaps.gui.elements.ExceptionDialog;
import org.tiberiumlabs.lailaps.list.ListStorage;
import org.tiberiumlabs.lailaps.settings.ApplicationSettings;
import org.tiberiumlabs.lailaps.settings.Settings;
import org.tiberiumlabs.lailaps.settings.gui.OptionsWindow;
import org.tiberiumlabs.lailaps.settings.helpers.LookAndFeelHelper;
import org.tiberiumlabs.lailaps.toolkit.Constants;
import org.tiberiumlabs.lailaps.tray.TrayFactory;
import org.tiberiumlabs.logging.SingleLog;
import org.tiberiumlabs.swing.DesktopToolkit;

/**
 *
 * @author <a href="mailto:paranoid.tiberiumlabs@gmail.com">Paranoid</a>
 */
public class Initializer {

    private static final String IDENTIFICATION_STRING = "Lailaps v0.1";
    private static final String NOURL = "nourl";

    private boolean firstRun = false;

    /** Creates a new instance of Initializer
     * @param args arguments from command line
     */
    public Initializer(final String[] args) {

        // <editor-fold defaultstate="collapsed" desc=" write params to socket ">
        // if settings not null - get port and write url. then return to exit program.
        int port = getPort();

        if (port > 0) {
            try {

                Socket client = new Socket("127.0.0.1", port);

                // connection established -> sending URL to acive instance
                PrintWriter out = new PrintWriter(client.getOutputStream(), true);
                out.println(IDENTIFICATION_STRING);

                if (args == null || args.length <= 0) {
                    //no params -> bring window to front
                    out.println(NOURL);
                }
                else {
                    //sending URL to open
                    out.println(args[0]);
                }

                out.close();
                client.close();

                //all done, exiting...
                return;
            } catch (Exception ignore) {
            }
        }
        // </editor-fold>

        // if we still here - there is no other instance of settings

        applyStartupParameters();

        firstRunSequence();

        LogFactory.getLog(Initializer.class).info("[ INITIALIZER ] initializations starts");

        // <editor-fold defaultstate="collapsed" desc=" setting up locale ">
        if (!Settings.getApplicationSettings().isUseSystemLocale()) {
            String userLocale = Settings.getApplicationSettings().getCustomLocale();
            if (userLocale.equals(Constants.ENGLISH_LNG)) {
                Locale.setDefault(Locale.US);
            } else if (userLocale.equals(Constants.RUSSIAN_LNG)) {
                Locale.setDefault(new Locale("ru", "RU"));
            } else if (userLocale.equals(Constants.UKRAINIAN_LNG)) {
                Locale.setDefault(new Locale("uk", "UA"));
            }
        }
        // </editor-fold>

        setLookAndFeel();
        ListStorage listStorage = new ListStorage();
        listStorage.loadList();
        listStorage.loadHistory();
        if (firstRun) {

            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    JFrame settingsFrame = new JFrame("Lailaps Settings");
                    settingsFrame.setContentPane(new OptionsWindow(settingsFrame, true));
                    settingsFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
                    settingsFrame.addWindowListener(new SettingsListener(args));
                    settingsFrame.pack();
                    settingsFrame.setLocation(DesktopToolkit.getWindowLocation(settingsFrame.getSize()));
                    settingsFrame.setVisible(true);
                }
            });
        } else {

            Thread listener = new Thread(new SocketListener(), "Instance Socket listener");
            listener.setDaemon(true);
            listener.start();

            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    createAndShowGUI();
                }
            });
            if (args != null && args.length > 0) {
                new EditDownloadDialog(args[0]);
            }
        }
        TrayFactory.createTrayIcon();
    }

    private int getPort() {
        int port = 0;

        File portFile = new File(Settings.getPortFile());
        if (portFile.exists()) {
            try {

                FileInputStream in = new FileInputStream(portFile);

                byte[] b = new byte[(int)portFile.length()];

                int read = in.read(b);
                port = Integer.parseInt(new String(b, 0, read));

                in.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return port;
    }

    private void firstRunSequence() {
        if (!Settings.loadSettings()) {
            firstRun = true;
        }
    }

    private void applyStartupParameters() {
        System.setProperty("awt.useSystemAAFontSettings", "on");
        System.setProperty("swing.boldMetal", "false");

        if (Settings.isDebugMode()) {
            SingleLog.init(SingleLog.DEBUG, System.out);
        }
        else {
            SingleLog.init(SingleLog.INFO, ApplicationSettings.LOG_FILE);
        }
    }

    private void createAndShowGUI() {
        // work with systray icon
        //createSysTrayIcon();
        GUIBuilder guiBuilder = Mediator.getMediator().getGuiBuilder();

        // TODO after systemTray will be implemented - redesign this behavior
        boolean showMain = Settings.getInterfaceSettings().isShowMainWindowOnStart();
        boolean showTarget = Settings.getInterfaceSettings().isShowDropTargetOnStart();
        if (showMain) {
            JFrame mainFrame = guiBuilder.getMainWindow();
            mainFrame.setVisible(true);
            mainFrame.requestFocusInWindow();
            if (showTarget) {
                JWindow dropTarget = guiBuilder.getDropTarget();
                dropTarget.setVisible(true);
            }
        } else {
            if (showTarget) {
                JWindow dropTarget = guiBuilder.getDropTarget();
                dropTarget.setVisible(true);
            } else {
                JFrame mainFrame = guiBuilder.getMainWindow();
                mainFrame.setVisible(true);
            }
        }
    }

    private void setLookAndFeel() {
        LookAndFeelHelper.startupInitialization();
    }

    private static class SocketListener implements Runnable {

        @Override
        public void run() {
            ServerSocket serverSocket = null;
            try {
                serverSocket = new ServerSocket(Settings.getApplicationSettings().getPort());
                while (true) {
                    Socket ssocket = serverSocket.accept();

                    BufferedReader in = new BufferedReader(new InputStreamReader(ssocket.getInputStream()));

                    if (in.readLine().equals(IDENTIFICATION_STRING)) {
                        // other Lailaps instance runed
                        // waiting for instructions...
                        String command = in.readLine();

                        if (command.equals(NOURL)) {
                            GUIBuilder guiBuilder = Mediator.getMediator().getGuiBuilder();
                            if (guiBuilder.isMainWindowVisible()) {
                                guiBuilder.getMainWindow().toFront();
                            }
                            else {
                                guiBuilder.getMainWindow().setVisible(true);
                            }
                        } else {
                            new EditDownloadDialog(command);
                        }
                    }

                    in.close();
                    ssocket.close();
                }
            } catch (IOException ex) {
                new ExceptionDialog(ex);
            } finally {
                try {
                    serverSocket.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

    private class SettingsListener implements WindowListener {

        private String inputUrl = null;

        public SettingsListener(String[] args) {
            if (args != null && args.length > 0) {
                inputUrl = args[0];
            }
        }

        @Override
        public void windowClosed(WindowEvent e) {
            Thread listener = new Thread(new SocketListener(), "Instance Socket listener");
            listener.setDaemon(true);
            listener.start();

            if (inputUrl != null) {
                new EditDownloadDialog(inputUrl);
            }
        }

        // <editor-fold defaultstate="collapsed" desc=" just implementing interface ">
        @Override
        public void windowOpened(WindowEvent e) {
        }

        @Override
        public void windowClosing(WindowEvent e) {
        }

        @Override
        public void windowIconified(WindowEvent e) {
        }

        @Override
        public void windowDeiconified(WindowEvent e) {
        }

        @Override
        public void windowActivated(WindowEvent e) {
        }

        @Override
        public void windowDeactivated(WindowEvent e) {
        }
        // </editor-fold>
    }
}
